/*
 * @Author: wwssaabb
 * @Date: 2021-09-03 17:24:26
 * @LastEditTime: 2021-12-13 09:00:19
 * @FilePath: \handwritten-code\main\call.js
 */

/* 
  call做了什么？
    改变this的指向
  call在哪里能够调用？
    function函数都可以调用，因此在Function的原型上
  call的参数怎么接收？
    可接收多个参数，apply只能接收数组

  思路：将this（调用call的函数）存储到新增的属性上，为避免属性污染用Symbol
        进行属性名创建，调用新增属性的函数，并进行传参，获取到结果之后再删除
        新增的属性，最后返回这个结果
  原理： 将函数放到需要绑定的对象身上进行调用 => 隐式绑定
*/

//ES6
Function.prototype.my_call=function(context=global,...args){
  const key=Symbol('key')
  context[key]=this
  let res=context[key](...args)
  delete context[key]
  return res
}

Function.prototype.my_call = function (context = global) {
  //context默认为全局对象
  //使用symbol创建属性名，防止原属性的覆盖
  const key = Symbol('key')
  //把this即当前调用的方法存储到传入对象的key属性中
  context[key] = this

  //获取剩下的参数，由于不使用ES6语法，需要使用到arguments对象，
  let args = Array.from(arguments).slice(1).map((_,index)=>`arguments[${index}]`)
  //执行this指向的函数,用eval运行字符串来执行函数起到参数展开的效果
  let res = eval('context[key](args.join(","))')
  //删除这个对象上的key属性
  delete context[key]
  return res
}

let p = {
  name: '张三',
  age: 18,
  say: function () {
    console.log(`我是${this.name},今年${this.age}岁`)
  }
}

let p1 = {
  name: '李四',
  age: 20,
}

p.say.my_call(p1)




//兼容性
Function.prototype.myCall=function(context=global){
  const key=Symbol('key')
  context[key]=this

  let res=context[key](...args)
  delete context[key]
  return res
}